package com.xue.apitest.utils;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.xue.apitest.constant.Constant;
import com.xue.apitest.constant.API;
import com.xue.apitest.constant.Cases;
import com.xue.apitest.constant.WriteBackData;
import org.apache.poi.ss.usermodel.*;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author xue
 * @Date 2021/6/19 12:14
 */
public class ExcelUtils {

    /**
     * 读取excel中第一个sheet,API， 通过read方法一次性把所有的接口数据都读取放到list集合里
     */
    public static List<API> apiList = readExcel(0, API.class);

    /**
     * 读取excel中第二个sheet,Case， 通过read方法一次性把所有的用例数据都读取放到list集合里
     */
    public static List<Cases> casesList = readExcel(1, Cases.class);

    /**
     * excel回写数据集合。
     */
    public static List<WriteBackData> wbdList = new ArrayList<>();

    /**
     * 读取Excel数据并转为List
     * @param startIndex 对应sheet表索引,从0开始
     * @param clazz      将读取的数据转为指定对象
     * @return           返回List的对象集合
     */
    public static <E> List<E> readExcel(int startIndex, Class<E> clazz){
        FileInputStream fis = null;
        try {
            //读取接口及测试用例文件
            fis = new FileInputStream(Constant.CASES_FILE_PATH);
            //导入配置，把excel内容读取到java中
            ImportParams params = new ImportParams();
            //设置需要读取的页签，以索引读取，默认是读取第一个页签
            params.setStartSheetIndex(startIndex);
            //设置在读取配置里需要验证数据，遇空则跳过
            params.setNeedVerify(true);
            //执行导入，导入的方法返回的是一个list集合，存的是对象，此时可以把excel接口信息表封装成一个对象
            return ExcelImportUtil.importExcel(fis, clazz, params);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            close(fis);
        }
        return null;
    }

    /**
     * 从已经读取好的所有List<API>和所有List<Case>两个集合中获取符合条件的数据
     * @param apiId  接口编号，用于匹配接口信息和用例 中的接口编口
     */
    public static Object[][] getAPIAndCasesByAPIId(String apiId){

        //需要的API对象，接口信息一个接口编号只有一个
        API wantAPI = null;

        //需要的Case集合，用例一个接口编号有多个用例，所有定义一个list集合
        List<Cases> wantCasesList = new ArrayList<>();

        //匹配API对象
        for (API api : apiList) {
            //传入的接口编号 与 API对象中的编号相等则返回
            //String.valueOf(int apiNumber)将int变量转换成字符串 ,因为equals比较的是字符串，也可以直接定义apiNumber为String类型
            if (apiId.equals(String.valueOf(api.getApiNumber()))) {
                wantAPI = api;
                break;
            }
        }
        //匹配Cases对象
        for (Cases cases : casesList) {
            //传入的接口编号和cases集合中的接口编号相等则返回
            if (apiId.equals(cases.getApiNumber())) {
                wantCasesList.add(cases);
            }
        }

        //在测试用例中采用的是注解@DataProvider参数化
        //该注解返回的是一个二维数组，所以此方法也返回一个二维数组
        //wantCaseList.size()是需要循环执行的用例次数，有多少个用例就执行几次
        Object[][] datas = new Object[wantCasesList.size()][2];
        //往二维数组中存储api和case数据，存几次由case确定。
        for (int i = 0; i < wantCasesList.size(); i++) {
            datas[i][0] = wantAPI;
            datas[i][1] = wantCasesList.get(i);
        }
        return datas;
    }

    /**
     * 批量回写
     * 确定需要回写的行、列、回写内容。列可以自定义一个固定的，放在常量类里
     */
    public static void batchWrite(){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //读取excel表格
            fis = new FileInputStream(Constant.CASES_FILE_PATH);
            //创建excel对象
            Workbook workbook = WorkbookFactory.create(fis);
            //读取需要打开的用例页签，以索引值读取
            Sheet sheet = workbook.getSheetAt(1);
            //回写，操作行和列
            //遍历wbdList集合
            for (WriteBackData wbd : wbdList) {
                //获取行号及行对象
                int rowNum = wbd.getRowNum();
                Row row = sheet.getRow(rowNum);
                //获取列号及列对象
                int cellNum = wbd.getCellNum();
                Cell cell = row.getCell(cellNum, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                //获取回写内容，设置到表格中
                cell.setCellType(CellType.STRING);
                String content = wbd.getContent();
                cell.setCellValue(content);
            }
            //内容回写到文件中
            fos = new FileOutputStream(Constant.CASES_FILE_PATH);
            workbook.write(fos);

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            close(fis);
            close(fos);
        }
    }

    /**
     * 流关闭方法
     * Closeable 这个接口只有一个关闭的方法 帮助一些需要关闭的类
     * @param stream 流对象
     */
    private static void close(Closeable stream){
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {

    }
}
